home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / mail / readers / xmail_1.000 / xmail_1 / xmail_1.6 / callMail.c < prev    next >
C/C++ Source or Header  |  1995-01-27  |  10KB  |  312 lines

  1. /*
  2.  * xmail - X window system interface to the mail program
  3.  *
  4.  * Copyright 1990,1991,1992 by National Semiconductor Corporation
  5.  *
  6.  * Permission to use, copy, modify, and distribute this software and its
  7.  * documentation for any purpose is hereby granted without fee, provided that
  8.  * the above copyright notice appear in all copies and that both that
  9.  * copyright notice and this permission notice appear in supporting
  10.  * documentation, and that the name of National Semiconductor Corporation not
  11.  * be used in advertising or publicity pertaining to distribution of the
  12.  * software without specific, written prior permission.
  13.  *
  14.  * NATIONAL SEMICONDUCTOR CORPORATION MAKES NO REPRESENTATIONS ABOUT THE
  15.  * SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE.  IT IS PROVIDED "AS IS"
  16.  * WITHOUT EXPRESS OR IMPLIED WARRANTY.  NATIONAL SEMICONDUCTOR CORPORATION
  17.  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
  18.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  IN NO
  19.  * EVENT SHALL NATIONAL SEMICONDUCTOR CORPORATION BE LIABLE FOR ANY SPECIAL,
  20.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  21.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  22.  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  23.  * PERFORMANCE OF THIS SOFTWARE.
  24.  *
  25.  * Author:  Michael C. Wagnitz - National Semiconductor Corporation
  26.  *
  27. **  Xmail talks to mail through a pseudo terminal which is a pair of master
  28. **  and slave devices: /dev/pty?? and /dev/tty??, where ?? goes from p0 to
  29. **  zf (system dependent).  The terminal is opened for both read and write.
  30. **
  31. */
  32.  
  33. #include    "global.h"
  34. #include    <sys/stat.h>
  35. #include    <signal.h>
  36.  
  37. #if    defined(AIXV3) || defined(_IBMR2)
  38. #include    <sys/select.h>
  39. #endif
  40.  
  41. #if    !(defined(SYSV) || defined(linux)) || defined(clipper)
  42. #include    <sgtty.h>
  43. #else
  44. #include    <sys/termio.h>
  45. #include    <sys/sysmacros.h>
  46. #include    <fcntl.h>
  47. #if    defined(att)
  48. #include    <sys/stropts.h>
  49. #endif
  50. #endif
  51.  
  52. #if defined(sun) && defined(SVR4)
  53. #include <sys/file.h>
  54. #endif
  55.  
  56. #ifndef TTYDEV
  57. #ifdef        sco
  58. #define TTYDEV        "/dev/ptypxx"
  59. #else    /* !sco */
  60. #ifdef        hpux
  61. #define TTYDEV        "/dev/pty/ptyxx"
  62. #else    /* !hpux */
  63. #define    TTYDEV        "/dev/ptyxx"
  64. #endif    /* !sco */
  65. #endif    /* !hpux */
  66. #endif    /* !TTYDEV */
  67.  
  68. #ifndef PTYCHAR1
  69. #ifdef        sco
  70. #define PTYCHAR1    "0123456789abcdef"
  71. #else    /* !sco */
  72. #ifdef        hpux
  73. #define PTYCHAR1    "zyxwvutsrqp"
  74. #else    /* !hpux */
  75. #define    PTYCHAR1    "pqrstuvwxyz"
  76. #endif    /* !sco */
  77. #endif    /* !hpux */
  78. #endif    /* !PTYCHAR1 */
  79.  
  80. #ifndef PTYCHAR2
  81. #ifdef        hpux
  82. #define    PTYCHAR2    "fedcba9876543210"
  83. #else    /* !hpux */
  84. #define    PTYCHAR2    "0123456789abcdef"
  85. #endif    /* !hpux */
  86. #endif    /* !PTYCHAR2 */
  87.  
  88. int                mail_fd;        /* mail process master tty id */
  89. int                mailpid;        /* mail process id */
  90. int                mailInputId;        /* mail input id */
  91. char        pseudo_tty[20];
  92.  
  93.  
  94. /*
  95. ** @(#) openMaster - searches for and opens a pty master.  If it finds one,
  96. **             it returns the value of the file descriptor.  If not,
  97. **             it reports an error and terminates.  Portions of this
  98. **             routine were stolen from X11R4 xterm get_pty() sources.
  99. */
  100. int
  101. openMaster()
  102. {
  103.  static int    devindex = 0;
  104.  static int    letter = 0;
  105.  struct    stat    st_buf;
  106.  int        master;
  107.  
  108. #ifdef att
  109.  (void) strcpy(pseudo_tty, "/dev/ptmx");
  110.  if ((master = open(pseudo_tty, O_RDWR)) >= 0)
  111.     return(master);
  112. #else /* !att, need lots of code */
  113. #if defined(umips) || defined(sgi) && defined (SYSV)
  114.  int        c;
  115.  
  116.  (void) strcpy(pseudo_tty, "/dev/ptc");
  117.  master = open(pseudo_tty, O_RDWR);
  118.  if (master >= 0 && (fstat(master, &st_buf)) == 0) {
  119.     (void) sprintf(pseudo_tty, "/dev/ttyq%d", minor(st_buf.st_rdev));
  120. #if ! defined(sgi)
  121.     if ((c = open(pseudo_tty, O_RDWR)) < 0) {
  122.        (void) close (master);
  123.       } else {                /* got one! */
  124.        (void) close (c);
  125.        return(master);
  126.       }
  127. #else
  128.     return(master);
  129. #endif
  130.    }
  131. #else /* not (umips && SYSV) */
  132.  (void) strcpy(pseudo_tty, TTYDEV);
  133.  while (PTYCHAR1[letter]) {
  134.        pseudo_tty[strlen(pseudo_tty) - 2] = PTYCHAR1[letter];
  135.        pseudo_tty[strlen(pseudo_tty) - 1] = PTYCHAR2[0];
  136.  
  137.        if (stat(pseudo_tty, &st_buf) == 0)
  138.           while (PTYCHAR2[devindex]) {
  139.                 pseudo_tty[strlen(pseudo_tty) - 1] = PTYCHAR2[devindex];
  140.                 if ((master = open(pseudo_tty, O_RDWR)) >= 0)
  141.                    return(master);
  142.  
  143.                 devindex++;
  144.                }
  145.        devindex = 0;
  146.        (void) letter++;
  147.       }
  148. #endif /* umips || sgi && SYSV */
  149. #endif /* att */
  150. /*
  151. ** We were unable to allocate a pty master!  Report the error and terminate.
  152. */
  153.  XtError("xmail cannot open master/slave pipe connection");
  154.  /* NOTREACHED */
  155. } /* end - openMaster */
  156.  
  157.  
  158. /*
  159. ** @(#)openSlave() - open slave side of pipe
  160. */
  161. /* ARGSUSED */
  162. int
  163. openSlave(master)
  164. int    master;
  165. {
  166.  int        slave;
  167.  
  168. #ifdef att
  169.  char        *slaveName;
  170.  int        grantpt(), unlockpt();
  171.  char        *ptsname();
  172.  
  173.  if (grantpt(master) >= 0 &&
  174.     unlockpt(master) >= 0 &&
  175.     (slaveName = ptsname(master)) != NULL &&
  176.     (slave = open(slaveName, O_RDWR)) >= 0 &&
  177.     (void) ioctl(slave, I_PUSH, "ptem") >= 0 &&
  178.     (void) ioctl(slave, I_PUSH, "ldterm") >= 0)
  179.     return(slave);
  180. #else /* !att */
  181. #if defined(umips) || defined(sgi) && defined(SYSV)
  182.  struct    stat    st_buf;
  183.  
  184.  fstat(master, &st_buf);
  185.  (void) sprintf(pseudo_tty, "/dev/ttyq%d", minor(st_buf.st_rdev));
  186.  if ((slave = open(pseudo_tty, O_RDWR)) >= 0)
  187.     return(slave);                /* got one! */
  188. #else /* not (umips || sgi && SYSV) */
  189. #if defined(sco) || defined(hpux)
  190.  pseudo_tty[strlen(pseudo_tty) - 6] = 't';
  191. #else
  192.  pseudo_tty[strlen(pseudo_tty) - 5] = 't';
  193. #endif
  194.  if ((slave = open(pseudo_tty, O_RDWR)) >= 0)
  195.     return(slave);
  196. #endif
  197. #endif
  198.  return(-1);                /* look for more master/slave pairs */
  199. } /* openSlave */
  200.  
  201.  
  202. /*
  203. ** @(#)callMail() - fork child to execute mail and attach to xmail input
  204. */
  205. /* ARGSUSED */
  206. void
  207. callMail(argv)
  208. char *argv[];
  209. {
  210. #if defined(linux) || (defined(SYSV)  && !defined(clipper))
  211.  struct termio    tio;
  212. #else    
  213.  struct sgttyb    Sgtty;
  214. #endif
  215.  int        slave;            /* file descriptor to slave pty */
  216.  
  217.  
  218.  for (;;) {                /* find a pair, or master fails */
  219.      mail_fd = openMaster();
  220.      if ((slave = openSlave(mail_fd)) != -1)
  221.         break;
  222.     }
  223. /*
  224. ** Set minimal requirements for slave connection (no echo, no NL->CR, keep TABS)
  225. */
  226. #if defined(linux) || (defined(SYSV) && !defined(clipper))
  227.  (void) ioctl(slave, TCGETA, &tio);
  228.  tio.c_oflag &= ~(OCRNL|ONLCR|ONLRET|TABDLY);
  229.  tio.c_iflag &= ~IXOFF;
  230.  tio.c_iflag |= ICRNL;
  231.  tio.c_lflag &= ~(ISIG|ECHO);
  232.  tio.c_lflag |= ICANON;
  233.  (void) ioctl(slave, TCSETA, &tio);
  234. #else    
  235.  (void) ioctl(slave, TIOCGETP, &Sgtty);
  236.  Sgtty.sg_flags &= ~(ECHO|CRMOD|XTABS);
  237.  (void) ioctl(slave, TIOCSETP, &Sgtty);
  238. #endif
  239.  
  240.  mailpid = fork();
  241.  if (mailpid == -1) {
  242.     XtError("callMail could not fork the child process");
  243.    } else if (mailpid) { 
  244.              /* 
  245.               * Parent : close the slave side of pty
  246.               *          set the mail file descriptor to append mode
  247.               *          register mail input with X
  248.               */
  249.              (void) close(slave);
  250. #ifndef linux
  251.              (void) fcntl(mail_fd, F_SETFL, FAPPEND);
  252. #else
  253.              (void) fcntl(mail_fd, F_SETFL, O_APPEND);
  254. #endif
  255.              mailInputId = XtAddInput(mail_fd, (XtPointer)XtInputReadMask, readMail, (XtPointer)NULL);
  256.             } else { 
  257.              /* 
  258.               * Child : close X connection and mail_fd side of pty
  259.               *         redirect stdin, stdout, stderr of mail to pty
  260.               *         unbuffer output data from mail
  261.               *         exec mail with arguments
  262.               *
  263.               *         Use a select() call to delay starting the mail process
  264.               *         until our parent can close its slave side of the pipe.
  265.               *         Eliminates the parent hanging (for approximately 15
  266.               *         seconds) on the close because the child terminated for
  267.               *         lack of mail before the parent could issue its close.
  268.               */
  269.              int        readfds, width;
  270.              struct timeval    timeout;
  271.  
  272.              (void) close(ConnectionNumber(XtDisplay(toplevel)));
  273.  
  274.              timeout.tv_sec = 0; timeout.tv_usec = 250000; /* 0.25 seconds */
  275.              readfds = 1 << slave; width = slave + 1;
  276.  
  277.              (void) select(width, (fd_set *) &readfds, (fd_set *) NULL, (fd_set *) NULL, &timeout);
  278.  
  279.              (void) close(mail_fd);
  280.              (void) dup2(slave, 0);
  281.              (void) dup2(slave, 1);
  282.              (void) dup2(slave, 2);
  283.              if (slave > 2)
  284.                  (void) close(slave);
  285. #ifndef linux
  286.              (void) fcntl(1, F_SETFL, FAPPEND);
  287. #else
  288.              (void) fcntl(1, F_SETFL, O_APPEND);
  289. #endif
  290.              setbuf(stdout, (char *) NULL);
  291. #ifdef linux
  292.          /* ANSI highlighting loses for folder buttons. */
  293.          unsetenv("TERM");
  294. #endif
  295.              (void) execvp(argv[0], argv);
  296.              /*
  297.               * If we fail to make contact, we must re-establish access to
  298.               * the terminal screen that started us for our error message,
  299.               * because we don't want to send it up the xmail pipe.
  300.               * Also terminate our parent.
  301.               */
  302.              if ((slave = open("/dev/tty", O_RDWR)) != -1) {
  303.                 (void) dup2(slave, 1);
  304.                 (void) dup2(slave, 2);
  305.                 perror(argv[0]);
  306.                }
  307.              (void) kill(getppid(), SIGKILL);        /* kill our parent */
  308.              (void) exit(1);
  309.              /* NOTREACHED */
  310.             }
  311. } /* callMail */
  312.